package top.xzxsrq.common.utils;

import com.alibaba.fastjson.JSON;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 扩展lang3包的ObjectUtils
 *
 * @program: MyUtils
 * @create: 2021-09-23 21:11
 **/
public abstract class ObjectUtilsZX extends ObjectUtils {

    public static List<String> fieldsName(Object source) {
        return fieldsName(source.getClass());
    }

    public static List<String> fieldsName(Class<?> clazz) {
        if (clazz.getName().equals(Object.class.getName())) {
            return new LinkedList<>();
        }
        List<String> collect = Arrays.stream(clazz.getDeclaredFields())
                .map(Field::getName).collect(Collectors.toList());
        List<String> strings = fieldsName(clazz.getSuperclass());
        if (CollectionUtils.isNotEmpty(strings)) {
            collect.addAll(strings);
        }
        return collect;
    }

    /**
     * 获取所有的字段包括父类的
     * @param clazz
     * @return
     */
    public static List<Field> getFieldsAndSup(Class<?> clazz) {
        if (clazz.getName().equals(Object.class.getName())) {
            return new LinkedList<>();
        }
        List<Field> collect = Arrays
                .stream(clazz.getDeclaredFields())
                .collect(Collectors.toList());
        collect.addAll(getFieldsAndSup(clazz.getSuperclass()));
        return collect;
    }

    public static void setValue(Object source, String fieldName, Object value) {
        try {
            Field declaredField = ObjectUtilsZX.getField(source.getClass(), fieldName);
            if (declaredField == null) {
                return;
            }
            declaredField.setAccessible(true);
            declaredField.set(source, value);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    public static Object getValue(Object source, String fieldName) {
        Field field = getField(source.getClass(), fieldName);
        if (field == null) {
            throw new RuntimeException("没有找到字段");
        }
        try {
            return field.get(source);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Field getField(Class<?> clazz, String fieldName) {
        if (clazz.getName().equals(Object.class.getName())) {
            return null;
        }
        try {
            Field declaredField = clazz.getDeclaredField(fieldName);
            declaredField.setAccessible(true);
            return declaredField;
        } catch (NoSuchFieldException e) {
            return getField(clazz.getSuperclass(), fieldName);
        }
    }

    public static String[] getNullPropertyNames(Object source) {
        final BeanWrapper src = new BeanWrapperImpl(source);
        java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();

        Set<String> emptyNames = new HashSet<String>();
        for (java.beans.PropertyDescriptor pd : pds) {
            Object srcValue = src.getPropertyValue(pd.getName());
            if (srcValue == null) {
                emptyNames.add(pd.getName());
            }
        }
        String[] result = new String[emptyNames.size()];
        return emptyNames.toArray(result);
    }

    public static <T> T clone(final T obj) {
        if (obj instanceof List) {
            if (ObjectUtilsZX.isEmpty(obj)) {
                return (T) new LinkedList<T>();
            }
            Class<?> aClass = ((List) obj).get(0).getClass();
            String s = JSON.toJSONString(obj);
            List<T> objects = (List<T>) JSON.parseArray(s, aClass);
            return (T) objects;
        }
        return ObjectUtils.clone(obj);
    }

    /**
     * 判断是不是基础类型
     *
     * @param value
     * @return
     */
    public static boolean isBaseType(Object value) {
        Class<?>[] notAdd = new Class[]{
                String.class,
                Character.class,
                Boolean.class,
                Integer.class,
                Double.class,
                Float.class,
                Long.class,
                Short.class,
                Byte.class,
                Number.class
        };
        for (Class<?> o : notAdd) {
            if (o.isAssignableFrom(value.getClass())) {
                return true;
            }
        }
        return false;
    }
}
